package
{
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class Population
	{
		
		static public const TRACK_WIDTH:Number = 10;
		
		public var maxMutationCount:Number = 5;
		
		public function Population()
		{
		}
		
		public var chromosomes:Vector.<Chromosome> ;
		
		public function generateRandom(count:Number):void
		{
			chromosomes = new Vector.<Chromosome>();
			
			for (var i:int = 0; i < count; i++) 
			{
				var chromosome:Chromosome = new Chromosome();
				chromosome.generateRandom();
				chromosomes.push(chromosome);
			}
			
		}
		
		private var _generation:Number = 0;

		public function get generation():Number
		{
			return _generation;
		}

		public function nextGeneration(track:Track):void
		{
			chromosomes = select(track);
			chromosomes = crossover();
			chromosomes = mutate();
			
			_generation++;
		}
		
		protected function select(track:Track):Vector.<Chromosome>
		{
			var lastfitValue:Number = 0;
			for each (var chromosome:Chromosome in chromosomes) 
			{
				var fitValue:Number = chromosome.fitness(track);
				//trace(fitValue);
				chromosome.fitnessRect = new Rectangle(lastfitValue, 0, fitValue, 3);
				lastfitValue += fitValue;
			}
			
			var selected:Vector.<Chromosome> = new Vector.<Chromosome>();
			for (var i:int = 0; i < chromosomes.length; i++) 
			{
				selected.push(getSelectedChromosome(Math.random()*lastfitValue));
			}
			
			return selected;
		}
		
		private function getSelectedChromosome(value:Number):Chromosome
		{
			for each (var c:Chromosome in chromosomes) 
			{
				if(c.fitnessRect.contains(value, 2))
					return c.clone();
			}
			
			return null;
		}
		
		protected function crossover():Vector.<Chromosome>
		{
			var c:Vector.<Chromosome> = chromosomes.slice();
			for (var i:int = 0; i < c.length-1; i+=2) 
			{
				var c1:Chromosome = c[i];
				var c2:Chromosome = c[i+1];
				
				var cpos:Number = Math.round(Math.random()*c1.data.length);
				/*var c1Ext:Vector.<Number> = c1.data.splice(0, cpos);
				var c2Ext:Vector.<Number> = c2.data.splice(cpos, c2.data.length-cpos-1);*/
				
				var newC1:Vector.<Number> = new Vector.<Number>();
				newC1 = newC1.concat(c2.data.slice(0, cpos));
				newC1 = newC1.concat(c1.data.slice(cpos));
				
				var newC2:Vector.<Number> = new Vector.<Number>();
				newC2 = newC2.concat(c1.data.slice(0, cpos));
				newC2 = newC2.concat(c2.data.slice(cpos));
				
				c1.data = newC1;
				c2.data = newC2;
			}
			
			return c;
		}
		
		protected function mutate():Vector.<Chromosome>
		{
			var count:Number = Math.round(Math.random()*maxMutationCount);
			
			for (var i:int = 0; i < count; i++) 
			{
				mutateChromosome();
			}
			
			return chromosomes;
		}
		
		private function mutateChromosome():void
		{
			var itemIndex:Number = Math.round(Math.random()*(chromosomes.length-1));
			var mutationIndex:Number = Math.round(Math.random()*(Chromosome.SIZE-1));
			
			chromosomes[itemIndex].data[mutationIndex] = Math.round(Math.random()*2-1);
		}
	}
}